#ifndef IBUFFER_H
#define IBUFFER_H

#pragma once

// disable the performance warnings for usage of bool in the template
#pragma warning(disable: 4800)
// disable the warnings for usage of '*=' with bool in the template
#pragma warning(disable: 4804)

#include <IBuffer/IBufferLayer.h>

#include <vector>


/**
 * This class is the template for an i-buffer. An i-buffer is a data structure
 * that holds information regarding interaction aspects of an object. When
 * several such buffers are combined and interactions are defined among them,
 * complex behaviors can be achieved for components that make use of the
 * buffers to determine their states. These buffers were originally created to
 * speed up interaction in applications for large displays (such as the
 * SmartTable and the SmartBoard) with a large number of components/widgets.
 *
 * This class is refatored from the original version of the i-buffer written by
 * T. Isenberg, A. Miede, and T. Zuk in the University of Calgary.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @since May 22, 2007
 */
template<class IBUFFERLAYER_API BufferBaseClass> class IBUFFERLAYER_API IBuffer
{
	// Attributes
protected:
	/** The i-buffer data */
	BufferBaseClass *_buffer;
	/** A look-up table (LUT) for easier 2D access to the buffer */
	BufferBaseClass **_bufferLUT;
	
	/** Horizontal dimension of the buffer data array */
	unsigned int _realWidth;
	/** Vertical dimension of the buffer data array */
	unsigned int _realHeight;
	/** Horizontal dimension of the buffer as is seen by the user */
	unsigned int _virtualWidth;
	/** Vertical dimension of the buffer as is seen by the user */
	unsigned int _virtualHeight;

	/** Number of channels in a buffer entry */
	unsigned int _nChannels;
	/** Number of bytes per channel of an entry */
	unsigned int _bytesPerChannel;
	/** The number of entries in the buffer */
	unsigned int _nEntries;
	/** The number of bytes in a buffer entry (number of channels * bytes per channel) */
	unsigned int _bytesPerEntry;
	/** The number of bytes in the buffer (number of entries * bytes per entry) (AKA byte depth) */
	unsigned int _nBytes;
	/** Sum of the number individual channels in all entries (number of entries * number of channels */
	unsigned int _nChannelEntries;

	/** The idenfier of this buffer */
	unsigned int _id;


	// Methods
public:
	/**
	 * Default constructor for the i-buffer.
	 */
	IBuffer(void);
	/**
	 * Constructor for the i-buffer that takes the buffer id  and, optionally,
	 * the number of channels as arguments.
	 *
	 * @param id the id of the i-buffer being created.
	 * @param nChannels the number of channels in each entry of the i-buffer.
	 */
	IBuffer(unsigned int id, unsigned int nChannels = 1);
	/**
	 * Constructor for the i-buffer that takes the buffer id, the number of
	 * channels, and the real and virtual dimensions as arguments.
	 *
	 * @param id the id of the i-buffer being created
	 * @param nChannels number of channels in each buffer entry
	 * @param realWidth the width of the buffer data structure
	 * @param realHeight the height of the buffer data structure
	 * @param virtualWidth the visible width of the buffer
	 * @param virtualHeight the visible height of the buffer
	 */
	IBuffer(unsigned int id, unsigned int nChannels, unsigned int realWidth,
		unsigned int realHeight, unsigned int virtualWidth, unsigned int virtualHeight);
	/**
	 * Destructor for the i-buffer.
	 */
	~IBuffer(void);

	/**
	 * Initializes the buffer with default values.
	 *
	 * @param id the id of the i-buffer being created
	 * @param nChannels number of channels in each buffer entry
	 * @param realWidth the width of the buffer data structure
	 * @param realHeight the height of the buffer data structure
	 * @param virtualWidth the visible width of the buffer
	 * @param virtualHeight the visible height of the buffer
	 */
	void init(unsigned int id = 0, unsigned int nChannels = 1,
		unsigned int realWidth = 10, unsigned int realHeight = 5,
		unsigned int virtualWidth = 20, unsigned int virtualHeight = 10);
	/**
	 * Destroys this buffer.
	 */
	void destroy(void);
	/**
	 * Sets the real and virtual dimensions of this buffer, (re-)allocating
	 * memory for it. When resizing, the values previously in the buffer are
	 * discarded and the new buffer entries have undefined values (garbage).
	 * The user should fill the buffer again in order to use it. The real
	 * dimensions are the dimensions of the actual buffers data structure and
	 * the virtual dimensions are the dimensions that the user "believes" the
	 * buffer is.
	 *
	 * @param realWidth the width of the buffer data structure
	 * @param realHeight the height of the buffer data structure
	 * @param virtualWidth the visible width of the buffer
	 * @param virtualHeight the visible height of the buffer
	 *
	 * @throw std::out_of_range when the interpolating indices fall out of the
	 * buffer bounds.
	 */
	void resize(unsigned int realWidth, unsigned int realHeight,
		unsigned int virtualWidth, unsigned int virtualHeight);
	/**
	 * Sets the real and virtual dimensions of this buffer, (re-)allocating
	 * memory for it. When resizing, the values previously in the buffer are
	 * interpolated to better fit in the new dimensions. The real dimensions
	 * are the dimensions of the actual buffers data structure and the virtual
	 * dimensions are the dimensions that the user "believes" the buffer is.
	 *
	 * @param realWidth the width of the buffer data structure
	 * @param realHeight the height of the buffer data structure
	 * @param virtualWidth the visible width of the buffer
	 * @param virtualHeight the visible height of the buffer
	 *
	 * @throw std::out_of_range when the interpolating indices fall out of the
	 * buffer bounds.
	 */
	void resizeInterpolation(unsigned int realWidth, unsigned int realHeight,
		unsigned int virtualWidth, unsigned int virtualHeight);
	/**
	 * Sets the real and virtual dimensions of this buffer, (re-)allocating
	 * memory for it. When resizing, the values previously in the buffer are
	 * kept and, if the new dimensions are bigger than the previous, the given
	 * filling value is used for the new area. The real dimensions are the
	 * dimensions of the actual buffers data structure and the virtual
	 * dimensions are the dimensions that the user "believes" the buffer is.
	 *
	 * @param realWidth the width of the buffer data structure
	 * @param realHeight the height of the buffer data structure
	 * @param virtualWidth the visible width of the buffer
	 * @param virtualHeight the visible height of the buffer
	 * @param fillValue the value to used to fill the new area, if the buffer
	 * is made bigger.
	 */
	void resizeCopy(unsigned int realWidth, unsigned int realHeight,
		unsigned int virtualWidth, unsigned int virtualHeight,
		BufferBaseClass* fillValue);
	/**
	 * Sets the real and virtual dimensions of this buffer, (re-)allocating
	 * memory for it. When resizing, the values previously in the buffer are
	 * replaced by given filling value. The real dimensions are the
	 * dimensions of the actual buffers data structure and the virtual
	 * dimensions are the dimensions that the user "believes" the buffer is.
	 *
	 * @param realWidth the width of the buffer data structure
	 * @param realHeight the height of the buffer data structure
	 * @param virtualWidth the visible width of the buffer
	 * @param virtualHeight the visible height of the buffer
	 * @param fillValue the value to used to fill the new buffer.
	 */
	void resizeFill(unsigned int realWidth, unsigned int realHeight,
		unsigned int virtualWidth, unsigned int virtualHeight,
		BufferBaseClass* fillValue);

	/**
	 * Clears the buffer by setting all its entries to a default value.
	 */
	void clear(void);
	/**
	 * Fills the buffer with the given value.
	 *
	 * @param value the value to set to the whole buffer.
	 */
	void fill(BufferBaseClass value);
	/**
	 * Fills the buffer with the given values for each channel.
	 *
	 * @param values the array of values to set to the whole multi-channel buffer.
	 */
	void fill(BufferBaseClass *values);

	/**
	 * Fills a quad region inside the buffer with the given value. It uses a
	 * slightly modified Active Edge Table (AET) fill algorithm, since the
	 * number of edges is constant (4).
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param value the value to be set inside the quad in the buffer.
	 */
	void fillQuad(unsigned int p0X, unsigned int p0Y,
		unsigned int p1X, unsigned int p1Y, unsigned int p2X, unsigned int p2Y,
		unsigned int p3X, unsigned int p3Y, BufferBaseClass value);
	/**
	 * Fills a quad region inside the buffer with the given value. It uses a
	 * slightly modified Active Edge Table (AET) fill algorithm, since the
	 * number of edges is constant (4). This methods takes the number of
	 * channels as parameter to avoid accessing a class variable to speed up
	 * processing.
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param values the array of channel values to be set inside the quad
	 * in the buffer.
	 * @param n the number of channels in the buffer (to speed things up)
	 */
	void fillQuad(unsigned int p0x, unsigned int p0y,
		unsigned int p1x, unsigned int p1y,
		unsigned int p2x, unsigned int p2y,
		unsigned int p3x, unsigned int p3y,
		BufferBaseClass *values, unsigned int n);
	/**
	 * Fills a quad region inside the buffer by interploating the given values.
	 * It uses a slightly modified Active Edge Table (AET) fill algorithm,
	 * since the number of edges is constant (4).
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param v0 the value of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param v1 the value of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param v2 the value of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param v3 the value of the fourth point in the quad.
	 */
	void fillQuad(unsigned int p0x, unsigned int p0y, BufferBaseClass v0,
		unsigned int p1x, unsigned int p1y, BufferBaseClass v1,
		unsigned int p2x, unsigned int p2y, BufferBaseClass v2,
		unsigned int p3x, unsigned int p3y, BufferBaseClass v3);
	/**
	 * Fills a quad region inside the buffer by interploating the given values.
	 * It uses a slightly modified Active Edge Table (AET) fill algorithm,
	 * since the number of edges is constant (4). This methods takes the number
	 * of channels as parameter to avoid accessing a class variable to speed up
	 * processing.
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param v0 the value of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param v1 the value of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param v2 the value of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param v3 the value of the fourth point in the quad.
	 * @param n the number of channels in the buffer (to speed things up)
	 */
	void fillQuad(unsigned int p0x, unsigned int p0y, BufferBaseClass *v0,
	   unsigned int p1x, unsigned int p1y, BufferBaseClass *v1,
	   unsigned int p2x, unsigned int p2y, BufferBaseClass *v2,
	   unsigned int p3x, unsigned int p3y, BufferBaseClass *v3,
	   unsigned int n);
	/**
	 * Fills a quad region inside the buffer by interploating the given values
	 * considering their length (interpreted as vectors). It uses a slightly
	 * modified Active Edge Table (AET) fill algorithm, since the number of
	 * edges is constant (4).
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param v0 the value of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param v1 the value of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param v2 the value of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param v3 the value of the fourth point in the quad.
	 * @param n the number of channels in the buffer (to speed things up).
	 */
	void fillQuadWithLength(
		unsigned int p0x, unsigned int p0y, BufferBaseClass *v0,
		unsigned int p1x, unsigned int p1y, BufferBaseClass *v1,
		unsigned int p2x, unsigned int p2y, BufferBaseClass *v2,
		unsigned int p3x, unsigned int p3y, BufferBaseClass *v3,
		unsigned int n);

	/**
	 * Fills a quad region inside the virtual buffer with the given value. It
	 * uses a slightly modified Active Edge Table (AET) fill algorithm, since
	 * the number of edges is constant (4).
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param value the value to be set inside the quad in the virtual buffer.
	 */
	void fillVirtualQuad(unsigned int p0x, unsigned int p0y,
		unsigned int p1x, unsigned int p1y, unsigned int p2x, unsigned int p2y,
		unsigned int p3x, unsigned int p3y, BufferBaseClass value);
	/**
	 * Fills a quad region inside the virtual buffer with the given value. It
	 * uses a slightly modified Active Edge Table (AET) fill algorithm, since
	 * the number of edges is constant (4). This methods takes the number of
	 * channels as parameter to avoid accessing a class variable to speed up
	 * processing.
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param values the array of channel values to be set inside the quad
	 * in the virtual buffer.
	 * @param n the number of channels in the buffer (to speed things up)
	 */
	void fillVirtualQuad(unsigned int p0x, unsigned int p0y,
		unsigned int p1x, unsigned int p1y,
		unsigned int p2x, unsigned int p2y,
		unsigned int p3x, unsigned int p3y,
		BufferBaseClass *values, unsigned int n);
	/**
	 * Fills a quad region inside the virtual buffer by interploating the given
	 * values. It uses a slightly modified Active Edge Table (AET) fill
	 * algorithm, since the number of edges is constant (4).
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param v0 the value of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param v1 the value of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param v2 the value of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param v3 the value of the fourth point in the quad.
	 */
	void fillVirtualQuad(unsigned int p0x, unsigned int p0y, BufferBaseClass v0,
		unsigned int p1x, unsigned int p1y, BufferBaseClass v1,
		unsigned int p2x, unsigned int p2y, BufferBaseClass v2,
		unsigned int p3x, unsigned int p3y, BufferBaseClass v3);
	/**
	 * Fills a quad region inside the virtual buffer by interploating the given
	 * values. It uses a slightly modified Active Edge Table (AET) fill
	 * algorithm, since the number of edges is constant (4). This methods takes
	 * the number of channels as parameter to avoid accessing a class variable
	 * to speed up processing.
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param v0 the value of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param v1 the value of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param v2 the value of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param v3 the value of the fourth point in the quad.
	 * @param n the number of channels in the virtual buffer (to speed things up)
	 */
	void fillVirtualQuad(unsigned int p0x, unsigned int p0y, BufferBaseClass *v0,
	   unsigned int p1x, unsigned int p1y, BufferBaseClass *v1,
	   unsigned int p2x, unsigned int p2y, BufferBaseClass *v2,
	   unsigned int p3x, unsigned int p3y, BufferBaseClass *v3,
	   unsigned int n);
	/**
	 * Fills a quad region inside the virtual buffer by interploating the given
	 * values considering their length (interpreted as vectors). It uses a
	 * slightly modified Active Edge Table (AET) fill algorithm, since the
	 * number of edges is constant (4).
	 *
	 * @param p0x the x-coordinate index of the first point in the quad.
	 * @param p0y the y-coordinate index of the first point in the quad.
	 * @param v0 the value of the first point in the quad.
	 * @param p1x the x-coordinate index of the second point in the quad.
	 * @param p1y the y-coordinate index of the second point in the quad.
	 * @param v1 the value of the second point in the quad.
	 * @param p2x the x-coordinate index of the third point in the quad.
	 * @param p2y the y-coordinate index of the third point in the quad.
	 * @param v2 the value of the third point in the quad.
	 * @param p3x the x-coordinate index of the fourth point in the quad.
	 * @param p3y the y-coordinate index of the fourth point in the quad.
	 * @param v3 the value of the fourth point in the quad.
	 * @param n the number of channels in the virtual buffer (to speed things up).
	 */
	void fillVirtualQuadWithLength(
		unsigned int p0x, unsigned int p0y, BufferBaseClass *v0,
		unsigned int p1x, unsigned int p1y, BufferBaseClass *v1,
		unsigned int p2x, unsigned int p2y, BufferBaseClass *v2,
		unsigned int p3x, unsigned int p3y, BufferBaseClass *v3,
		unsigned int n);

	/**
	 * Fills a polygon with an arbitrary shape defined the given collection of
	 * vertices with the given value.
	 * This method is adapted from the original code written by Jens Grubert
	 * for the previous version of the framework and based on the Active Edge
	 * Table polygon filling algorithm describe in
	 * http://www.cs.rit.edu/~icss571/filling/how_to.html.
	 *
	 * @param points the collection of vertices of the polygon.
	 * @param value the value to be used to fill the buffer entries.
	 */
	void fillPolygon(std::vector< std::pair<int, int> > points, BufferBaseClass value);
	/**
	 * Fills a polygon with an arbitrary shape defined the given collection of
	 * vertices with the given multi-channel value.
	 * This method is adapted from the original code written by Jens Grubert
	 * for the previous version of the framework and based on the Active Edge
	 * Table polygon filling algorithm describe in
	 * http://www.cs.rit.edu/~icss571/filling/how_to.html.
	 *
	 * @param points the collection of vertices of the polygon.
	 * @param values the multi-channel value to be used to fill the buffer entries.
	 */
	void fillPolygon(std::vector< std::pair<int, int> > points, BufferBaseClass* values);


	/**
	 * Sets the given value to the given position in the i-buffer considering a
	 * virtual buffer.
	 *
	 * @param x the horizontal index of the entry to be set in the buffer.
	 * @param y the vertical index of the entry to be set in the buffer.
	 * @param value the value to be set in the given buffer position.
	 *
	 * @throw std::out_of_range when the indices are out of the buffer bounds.
	 */
	void setVirtualValue(unsigned int x, unsigned int y, BufferBaseClass value);
	/**
	 * Sets the given values to the given position in the multi-channel i-buffer
	 * considering a virtual buffer.
	 *
	 * @param x the horizontal index of the entry to be set in the buffer.
	 * @param y the vertical index of the entry to be set in the buffer.
	 * @param values the array of values to be set in each channel of the given
	 * buffer position.
	 *
	 * @throw std::out_of_range when the indices are out of the buffer bounds.
	 */
	void setVirtualValue(unsigned int x, unsigned int y, BufferBaseClass *values);
	/**
	 * Returns the value of the i-buffer at the given position considering a
	 * virtual buffer.
	 *
	 * @param x the horizontal index of the entry to be obtained from the buffer.
	 * @param y the vertical index of the entry to be obtained from the buffer.
	 *
	 * @return the value of the i-buffer at the given position.
	 *
	 * @throw std::out_of_range when the indices are out of the buffer bounds.
	 */
	BufferBaseClass getVirtualValue(unsigned int x, unsigned int y);
	/**
	 * Provides the value of the multi-channel i-buffer at the given position
	 * considering a virtual buffer.
	 *
	 * @param x the horizontal index of the entry to be obtained from the buffer.
	 * @param y the vertical index of the entry to be obtained from the buffer.
	 * @param values the array of values of the multi-channel entry.
	 *
	 * @throw std::out_of_range when the indices are out of the buffer bounds.
	 */
	void getVirtualValue(unsigned int x, unsigned int y, BufferBaseClass *values);
	/**
	 * Returns the interpolated value of the i-buffer at the given position
	 * considering a virtual buffer.
	 *
	 * @param x the horizontal index of the entry to be obtained from the buffer.
	 * @param y the vertical index of the entry to be obtained from the buffer.
	 *
	 * @return the value of the i-buffer at the given position.
	 *
	 * @throw std::out_of_range when the indices are out of the buffer bounds.
	 */
	BufferBaseClass getVirtualValue(double x, double y);
	/**
	 * Provides the interpolated value of the i-buffer at the given position
	 * considering a virtual buffer.
	 *
	 * @param x the horizontal index of the entry to be obtained from the buffer.
	 * @param y the vertical index of the entry to be obtained from the buffer.
	 * @param values the array of values of the multi-channel entry.
	 *
	 * @throw std::out_of_range when the indices are out of the buffer bounds.
	 */
	void getVirtualValue(double x, double y, BufferBaseClass *values);


	// INLINE FUNCTIONS
	/**
	 * Sets the given value to the given position in the real (not virtual)
	 * i-buffer. It doesn't check the range of the input values due to
	 * performance reasons. When calling this function, the indices must be
	 * inside the current buffer bounds.
	 *
	 * @param x the horizontal index of the entry to be set in the buffer.
	 * @param y the vertical index of the entry to be set in the buffer.
	 * @param value the value to be set in the given buffer position.
	 */
	inline void setValue(unsigned int x, unsigned int y, BufferBaseClass value)
	{
	///	if (!(x < _realWidth && y < _realHeight))
	//		throw std::out_of_range("IBuffer.setActualValue(): index out of buffer bounds");
		_bufferLUT[y][x] = value;
	}
	
	
	
	
	/**
	 * Sets the given values to the given position in the multi-channel real i-buffer.
	 *
	 * @param x the horizontal index of the entry to be set in the buffer.
	 * @param y the vertical index of the entry to be set in the buffer.
	 * @param values the array of values to be set in each channel of the given
	 * buffer position.
	 *
	 * @throw std::out_of_range when the indices are out of the buffer bounds.
	 */
	inline void setValue(unsigned int x, unsigned int y, BufferBaseClass *values)
	{
		if (!(x < _realWidth && y < _realHeight))
			throw std::out_of_range("IBuffer.setActualValue(): index out of buffer bounds");
		for (unsigned int i = 0, index = _nChannels * (x + y * _realWidth); i < _nChannels; i++, index++)
			_buffer[index] = values[i];
	}
	/**
	 * Sets the given values to the given position in the n-channel real i-buffer.
	 * It doesn't check the range of the input values due to performance reasons.
	 * When calling this function, the indices must be inside the current buffer
	 * bounds.
	 *
	 * @param x the horizontal index of the entry to be set in the buffer.
	 * @param y the vertical index of the entry to be set in the buffer.
	 * @param values the array of values to be set in each channel of the given
	 * buffer position.
	 * @param n the number of channels in the given value.
	 */
	inline void setValue(unsigned int x, unsigned int y, BufferBaseClass *values, const unsigned int n)
	{
		//if (!(x < _realWidth && y < _realHeight))
		//	throw std::out_of_range("IBuffer.setActualValue(): index out of buffer bounds");
		for (unsigned int i = 0, index = _nChannels * (x + y * _realWidth); i < n; i++, index++)
			_buffer[index] = values[i];
	}
	
	/**
	 * Returns the value of the real (not virtual) i-buffer at the given
	 * position. It doesn't check the range of the input values due to
	 * performance reasons. When calling this function, the indices must be
	 * inside the current buffer bounds.
	 *
	 * @param x the horizontal index of the entry to be obtained from the buffer.
	 * @param y the vertical index of the entry to be obtained from the buffer.
	 *
	 * @return the value of the real i-buffer at the given position.
	 */
	inline BufferBaseClass getValue(unsigned int x, unsigned int y)
	{
		//if (!(x < _realWidth && y < _realHeight))
		//	throw std::out_of_range("IBuffer.getActualValue(): index out of buffer bounds");
		return _bufferLUT[y][x];
	}
	/**
	 * Provides the value of the multi-channel real i-buffer at the given position.
	 * It doesn't check the range of the input values due to performance reasons.
	 * When calling this function, the indices must be inside the current buffer
	 * bounds.
	 *
	 * @param x the horizontal index of the entry to be obtained from the buffer.
	 * @param y the vertical index of the entry to be obtained from the buffer.
	 * @param values the array of values of the multi-channel entry.
	 */
	inline void getValue(unsigned int x, unsigned int y, BufferBaseClass *values)
	{
		//if (!(x < _realWidth && y < _realHeight))
		//	throw std::out_of_range("IBuffer.getActualValue(): index out of buffer bounds");
		for (unsigned int i = 0, index = (x + y * _realWidth) * _nChannels; i < _nChannels; i++, index++)
			values[i] = _buffer[index];
	}
	/**
	 * Provides the value of the n-channel real i-buffer at the given position.
	 * It doesn't check the range of the input values due to performance reasons.
	 * When calling this function, the indices must be inside the current buffer
	 * bounds.
	 *
	 * @param x the horizontal index of the entry to be obtained from the buffer.
	 * @param y the vertical index of the entry to be obtained from the buffer.
	 * @param values the array of values of the multi-channel entry.
	 * @param n the number of channels in the given value.
	 */
	inline void getValue(unsigned int x, unsigned int y, BufferBaseClass *values, const unsigned int n)
	{
		//if (!(x < _realWidth && y < _realHeight))
		//	throw std::out_of_range("IBuffer.getActualValue(): index out of buffer bounds");
		for (unsigned int i = 0, index = (x + y * _realWidth) * _nChannels; i < _nChannels; i++, index++)
			values[i] = _buffer[index];
	}

	/**
	 * Returns true if the given coordinates are inside the buffer current
	 * virtual dimensions.
	 *
	 * @param x the horizontal coordinate of the buffer entry.
	 * @param y the vertical coordinate of the buffer entry.
	 *
	 * @return true if the given coordinates are inside the buffer virtual
	 * dimensions, false otherwise.
	 */
	inline bool isInsideVirtualBuffer(double x, double y) {
		return ((x >= 0 && x <= _virtualWidth - 1)
			&& (y >= 0 && y <= _virtualHeight - 1));
	};
	/**
	 * Returns true if the given coordinates are inside the buffer current
	 * real dimensions.
	 *
	 * @param x the horizontal coordinate of the buffer entry.
	 * @param y the vertical coordinate of the buffer entry.
	 *
	 * @return true if the given coordinates are inside the buffer real
	 * dimensions, false otherwise.
	 */
	inline bool isInsideActualBuffer(double x, double y) {
		return ((x >= 0 && x <= _realWidth - 1)
			&& (y >= 0 && y <= _realHeight - 1));
	};
	

	
	// ACCESSOR METHODS
	/**
	 * Sets the id of this i-buffer.
	 *
	 * @param id the new id.
	 */
	void setId(unsigned int id);
	/**
	 * Returns the identifier of this i-buffer.
	 *
	 * @return the id of this i-buffer.
	 */
	unsigned int getId();
	/**
	 * Returns the current buffer size.
	 *
	 * @return the buffer size.
	 */
	unsigned int getNumberEntries(void);
	/**
	 * Returns the (virtual) width of the buffer.
	 *
	 * @return the width of this buffer.
	 */
	unsigned int getWidth();
	/**
	 * Returns the (virtual) height of the buffer.
	 *
	 * @return the height of this buffer.
	 */
	unsigned int getHeight();
	/**
	 * Returns the (real) width of the buffer data structure.
	 *
	 * @return the width of this buffer data structure.
	 */
	unsigned int getActualWidth();
	/**
	 * Returns the (real) height of the buffer data structure.
	 *
	 * @return the height of this buffer data structure.
	 */
	unsigned int getActualHeight();
	/**
	 * Returns the number of channels per buffer entry.
	 *
	 * @return the number of channels per buffer entry.
	 */
	unsigned int getNumberChannels();
	/**
	 * Returns the number of bytes in a buffer entry.
	 *
	 * @return number of bytes in a buffer entry.
	 */
	unsigned int getEntrySizeBytes(void);

	/**
	 * Returns the amount of memory allocated for this i-buffer in bytes.
	 *
	 * @return the total memory allocated for this i-buffer in bytes.
	 */
	unsigned long getAllocatedMemorySizeBytes(void);
	/**
	 * Returns the amount of memory allocated for this i-buffer in Kylobytes.
	 *
	 * @return the total memory allocated for this i-buffer in Kylobytes.
	 */
	unsigned long getAllocatedMemorySizeKBytes(void);


	// DEBUGGING METHODS
	/**
	 * Prints the current contents of the i-buffer to the console.
	 */
	void print(void);
	/**
	 * Creates an image with the buffer byte contents in the given ppm file.
	 * The buffer data is converted to unsigned bytes when added to the image.
	 * If the buffer data is not in the byte range (0 to 255), a scale factor
	 * and an offset can be defined so that the data is properly converted. If
	 * the buffer has more than 3 channels, more images are created with the
	 * additional information. The output file names are appended with integer
	 * numbers starting at zero.
	 *
	 * @param fileName the name of the ppm file to be loaded with the buffer data
	 * @param factor the scale factor to be applied to the buffer entry values
	 * @param offset the offset to be added to the buffer entry values
	 * @throw std::logic_error if the buffer doesn't have any channels
	 */
	void createImage(const char *fileName, double factor = 1.0, double offset = 0.0);
	

// PLEASE, DON'T CHANGE THE LINE BELOW! IT IS MANIPULATED DURING ANT BUILDING!
 protected: // This line should be commented out for unit testing!
	/**
	 * Sets up the buffer parameters.
	 *
	 * @param realWidth the width of the buffer data structure
	 * @param realHeight the height of the buffer data structure
	 * @param virtualWidth the visible width of the buffer
	 * @param virtualHeight the visible height of the buffer
	 */
	void setup(unsigned int realWidth, unsigned int realHeight,
		unsigned int virtualWidth, unsigned int virtualHeight);
	/**
	 * Allocates memory for the i-buffer and its look-up table. It uses the
	 * current properties to define the dimensions of the data structures.
	 */
	void allocateMemory(void);
	/**
	 * Calculates the value of the bilinear interpolation of the current buffer
	 * values for the given entry position. It uses the surrounding four
	 * entries to obtain the final interpolated value.
	 *
	 * @param x the horizontal coordinate of the buffer entry.
	 * @param y the vertical coordinate of the buffer entry.
	 *
	 * @throw std::out_of_range if the indices are out of the buffer bounds.
	 *
	 * @return the interpolated value at the given coordinates.
	 *
	 * @see http://en.wikipedia.org/wiki/Bilinear_interpolation
	 */
	BufferBaseClass interpolateEntry(double x, double y);
	/**
	 * Calculates the value of the bilinear interpolation of the current
	 * multi-channel buffer values for the given entry position. It uses the
	 * surrounding four entries to obtain the final interpolated values.
	 *
	 * @param x the horizontal coordinate of the buffer entry.
	 * @param y the vertical coordinate of the buffer entry.
	 * @param values the array of interpolated values of the multi-channel
	 * entry.
	 *
	 * @throw std::out_of_range if the indices are out of the buffer bounds.
	 *
	 * @see http://en.wikipedia.org/wiki/Bilinear_interpolation
	 */
	void interpolateEntry(double x, double y, BufferBaseClass *values);

	/**
	 * Returns the real coordinates based on the given virtual coordinates.
	 *
	 * @param x the virtual x-coordinate value
	 * @param y the virtual y-coordinate value
	 * @param realX the real x-coordinate value
	 * @param realY the real y-coordinate value
	 */
	inline void calculateRealCoordinates(unsigned int x, unsigned int y,
		unsigned int &realX, unsigned int &realY)
	{
		// The proportion conversion uses the actual indexing domain instead of the
		// nominal length in order to have results inside the expected range. A
		// simple rounding mechanism is used to get the final value.
		realX = (unsigned int) ((x * (_realWidth - 1.0)
			 / (float) (_virtualWidth - 1.0)) + 0.5);
			// / ((_virtualWidth == 1) ? (float) (_virtualWidth - 1.0) : 1.0)) + 0.5);
		realY = (unsigned int) ((y * (_realHeight - 1.0)
			 / (float) (_virtualHeight - 1.0)) + 0.5);
			// / ((_virtualHeight == 1) ? (float) (_virtualHeight - 1.0) : 1.0)) + 0.5);
	};
	
};


// FUNCTOR CLASSES USED FOR POLYGON FILLING
/**
 * This functor is used to compare a vector of doubles with following content:
 * vector[0] = yMin
 * vector[1] = yMax
 * vector[2] = xAtYMin
 * vector[3] = oneOverSlope
 *
 * For the given parameters, edge1 is smaller than edge 2 if its yMin is
 * smaller. If both yMin are equal, edge1 is still smaller if its xAtYMin is
 * smaller.
 *
 * @author Jens Grubert
 * @author Fabricio Anstacio (adaptation)
 * @since October 9, 2007
 */
class CompareEdgeEntries
{
public:
	int operator() (const std::vector<double> &edge1, const std::vector<double> &edge2) {
		if (edge1.at(0) < edge2.at(0)) return 1;
		else if (edge1.at(0) > edge2.at(0)) return 0;
		else if (edge1.at(2) < edge2.at(2)) return 1;
		else return 0;
	}
};

/**
 * This functor is used to compare active edge entries based on their x values.
 *
 * @author Jens Grubert
 * @author Fabricio Anstacio (adaptation)
 * @since October 9, 2007
 */
class CompareEdgeEntriesByX
{
public:
	int operator() (const std::vector<double> &edge1, const std::vector<double> &edge2) {		
		return (edge1.at(2) < edge2.at(2));
	}
};

#endif  // IBUFFER_H
